package modelo.automata;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Andres
 */
public class AutomataFinitoDeterminista extends AutomataFinito{

    /**
     * Crea un AFD vacio.
     */
    public AutomataFinitoDeterminista() {
        super();
    }

    /**
     *
     * @param conjuntoDeEstados
     * @param alfabetoEntrada
     * @param estadoInicial
     * @param conjuntoEstadosFinales
     * @param tablaDeTransiciones
     */
    public AutomataFinitoDeterminista(Collection<String> conjuntoDeEstados,
            Collection<String> alfabetoEntrada, String estadoInicial,
            Collection<String> conjuntoEstadosFinales, String[][] tablaDeTransiciones) {

        super(conjuntoDeEstados, alfabetoEntrada, estadoInicial, conjuntoEstadosFinales, tablaDeTransiciones);
    }

    /**
     * 
     * @param cadena
     * @return
     * @throws Exception 
     */
    @Override
    public boolean lectura(String[] cadena)  throws Exception {
        List<String> estados = new ArrayList<String>();
        for(int i=0;i<tablaDeTransiciones.length;i++)
            estados.add(tablaDeTransiciones[i][0]);
        
        List<String> caracteres = Arrays.asList(cadena);
        int estado = conjuntoDeEstados.indexOf(estadoInicial);
        int entrada;
        if(conjuntoDeEstados!=null && alfabetoEntrada!=null && 
                estadoInicial!=null && conjuntoEstadosFinales!=null && tablaDeTransiciones!=null) {
            for(int i = 0;i<cadena.length; i++) {
                entrada = alfabetoEntrada.indexOf(caracteres.get(0));
                estado = estados.indexOf(tablaDeTransiciones[estado][entrada]);
                System.out.println("Lectura de: "+caracteres.get(i)+", lleva al estado: "+tablaDeTransiciones[estado][entrada]);
            }
            return conjuntoEstadosFinales.contains(conjuntoDeEstados.get(estado))!=false;
        }else {
            throw new Exception("El estado inicial debe pertenecer al conjunto de estados");
        }
    }

    /**
     * 
     */
//    @Override
    public void eliminarEstadosInaccesibles() {
        List<String> estadosInaccesibles = new ArrayList<String>();
        for(String e:conjuntoDeEstados) {
            if(!existeCaminoA(e)) {
                estadosInaccesibles.add(e);
            }
        }
        
        conjuntoDeEstados.removeAll(estadosInaccesibles);
        conjuntoEstadosFinales.removeAll(estadosInaccesibles);
        String[][] tablaTMP = new String[conjuntoDeEstados.size()][alfabetoEntrada.size()];
        
        for(int i=0;i<tablaDeTransiciones.length;i++) {
            if(estadosInaccesibles.contains(tablaDeTransiciones[i][0])) {
                i++;
                if(i==tablaDeTransiciones.length)
                    break;
            }
            for(int j=0;j<tablaDeTransiciones[i].length;j++) {
                tablaTMP[i][j] = tablaDeTransiciones[i][j];
            }
        }
        
        tablaDeTransiciones = new String[conjuntoDeEstados.size()][alfabetoEntrada.size()];
        for(int i=0;i<tablaDeTransiciones.length;i++) {
            for(int j=0;j<tablaDeTransiciones[i].length;j++) {
                tablaDeTransiciones[i][j] = tablaTMP[i][j];
            }
        }
    }
    
    private boolean existeCaminoA(String estado) {
        boolean existe = false;
        for(int fil=0;fil<tablaDeTransiciones.length;fil++) {
            if(conjuntoDeEstados.indexOf(estado)==fil) {
                fil++;
                if(fil==tablaDeTransiciones.length)
                    break;
            }
            for(int col=0;col<tablaDeTransiciones[fil].length;col++) {
                if(tablaDeTransiciones[fil][col].equals(estado)) {
                    existe = true;
                    break;
                }
            }
        }
        return existe;
    }

    /**
     * 
     * @param af
     * @return 
     */
    @Override
    public boolean esEquivalente(AutomataFinito af) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     *
     * @param afd
     * @return
     */
    public AutomataFinitoDeterminista union(AutomataFinitoDeterminista afd) {
        AutomataFinitoDeterminista AFD = new AutomataFinitoDeterminista();
        
        return AFD;
    }

    /**
     *
     * @param afd
     * @return
     */
    public AutomataFinitoDeterminista interseccion(AutomataFinitoDeterminista afd) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     *
     * @param afd
     * @return
     */
    public AutomataFinitoDeterminista complemento(AutomataFinitoDeterminista afd) {
        AutomataFinitoDeterminista AFDcom = new AutomataFinitoDeterminista();
        List<String> nconjuntoDeEstados = conjuntoDeEstados.subList(0, conjuntoDeEstados.size()-1);
        List<String> nalfabetoEntrada = alfabetoEntrada.subList(0, alfabetoEntrada.size()-1);
        String nestadoInicial = estadoInicial;
        
        String[][] ntablaDeTransiciones = new String[conjuntoDeEstados.size()][alfabetoEntrada.size()];
        
        for(int fil=0;fil<tablaDeTransiciones.length;fil++) {
            for(int col=0;col<tablaDeTransiciones[fil].length;col++) {
                ntablaDeTransiciones[fil][col] = tablaDeTransiciones[fil][col];
            }
        }
        
        List<String> nconjuntoEstadosFinales = new ArrayList<String>();
        for(String f:nconjuntoDeEstados) nconjuntoEstadosFinales.add(f);
        nconjuntoEstadosFinales.removeAll(conjuntoEstadosFinales);
        
        return new AutomataFinitoDeterminista(nconjuntoDeEstados, 
                nalfabetoEntrada, nestadoInicial, nconjuntoEstadosFinales, ntablaDeTransiciones);
    }

    /**
     *
     * @return
     */
    public AutomataFinitoDeterminista minimizacion() {
        throw new UnsupportedOperationException("Not supported yet.");
    }
    
    /**
     * 
     * @param conjuntoDeEstados
     * @param tablaDeTransiciones
     * @return 
     */
    public static boolean esDeterminista(List<String> conjuntoDeEstados, 
                                        String[][] tablaDeTransiciones) {
        boolean determinista = true;
        for(String[] f:tablaDeTransiciones) {
            for(String g:f) {
                if(!conjuntoDeEstados.contains(g)) {
                    determinista = false;
                } 
            }
        }
        return determinista;
    }
}
